package tech.xs.common.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 数据同步工具
 *
 * @author 沈家文
 * @since 2023/7/3 20:12
 */
public class SyncUtil {

    public interface Compare<T> {

        /**
         * 对比时调用
         *
         * @param o1 参数1
         * @param o2 参数2
         * @return 对比结果
         */
        boolean compare(T o1, T o2);

        /**
         * 新增时调用
         *
         * @param source 源数据
         * @return 结果数据
         */
        default T sourceToTarget(T source) {
            return source;
        }

        /**
         * 更新时调用
         *
         * @param source 源数据
         * @param target 结果数据
         * @return 返回最终数据
         */
        default T sourceToTarget(T source, T target) {
            return source;
        }


    }


    /**
     * 数据对比工具类
     *
     * @param sourceList 新同步过来的数据
     * @param targetList 原始存储的数据
     * @param addList    对比之后新增的数据
     * @param updateList 对比之后需要更新的数据
     * @param deleteList 对比之后需要删除的数据
     * @param compare    对比函数
     * @param <E>        数据类型
     */
    public static <E> void contrast(Collection<E> sourceList, Collection<E> targetList, List<E> addList, List<E> updateList, List<E> deleteList, Compare<E> compare) {
        setAddList(sourceList, targetList, addList, compare);
        getUpdateDeleteList(sourceList, targetList, updateList, deleteList, compare);
    }

    private static <E> void getUpdateDeleteList(Collection<E> sourceList, Collection<E> targetList, List<E> updateList, List<E> deleteList, Compare<E> compare) {
        for (E target : targetList) {
            boolean isExist = false;
            for (E source : sourceList) {
                if (compare.compare(target, source)) {
                    updateList.add(compare.sourceToTarget(source, target));
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                deleteList.add(target);
            }
        }
        duplicate(updateList, compare);
    }

    /**
     * 去重
     *
     * @param list
     * @param compare
     * @param <E>
     */
    private static <E> void duplicate(Collection<E> list, Compare<E> compare) {
        List<E> newList = new ArrayList<>();
        for (E item1 : list) {
            boolean isExist = false;
            for (E item2 : newList) {
                if (compare.compare(item1, item2)) {
                    isExist = true;
                }
            }
            if (!isExist) {
                newList.add(item1);
            }
        }
        list.clear();
        list.addAll(newList);
    }


    private static <E> void setAddList(Collection<E> sourceList, Collection<E> targetList, List<E> addList, Compare<E> compare) {
        for (E source : sourceList) {
            boolean isExist = isExistListItem(addList, source, compare);
            if (!isExist) {
                isExist = isExistListItem(targetList, source, compare);
            }
            if (!isExist) {
                addList.add(compare.sourceToTarget(source));
            }
        }
    }

    private static <E> boolean isExistListItem(Collection<E> sourceList, E item, Compare<E> compare) {
        for (E sourceItem : sourceList) {
            if (compare.compare(sourceItem, item)) {
                return true;
            }
        }
        return false;
    }

}
